#!/usr/bin/env node

/**
 * 多关键词并行爬取脚本
 * 
 * 功能：支持单个任务使用多个关键词并行运行
 * 
 * 用法：
 *   node parallel-keywords-crawler.js --task amazon-jp
 *   node parallel-keywords-crawler.js --task amazon-jp --keywords "ベビーフード,おむつ,ベビー用品"
 *   node parallel-keywords-crawler.js --task amazon-jp --max-concurrent 3
 *   node parallel-keywords-crawler.js --task amazon-de --keywords "Baby Foods,Baby Toys"
 */

const { chromium } = require('playwright');
const { chromium: chromiumExtra } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth')();
const EcommerceCrawler = require('./ecommerce-crawler');
const config = require('./tasks.config');
const dbConnection = require('./db/connection');
const path = require('path');
const fs = require('fs');

// 解析命令行参数
function parseArgs() {
    const args = process.argv.slice(2);
    const options = {
        task: null,
        keywords: null,
        maxConcurrent: 5,
        headless: config.browser.headless,
        slowMo: 500,
        stealth: config.browser.stealth
    };
    
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        
        if ((arg === '--task' || arg === '-t') && i + 1 < args.length) {
            options.task = args[i + 1];
            i++;
        } else if ((arg === '--keywords' || arg === '-k') && i + 1 < args.length) {
            options.keywords = args[i + 1].split(',').map(k => k.trim());
            i++;
        } else if (arg === '--max-concurrent' && i + 1 < args.length) {
            options.maxConcurrent = parseInt(args[i + 1]);
            i++;
        } else if (arg === '--headless') {
            options.headless = true;
        } else if (arg === '--no-stealth') {
            options.stealth = false;
        } else if (arg === '--help' || arg === '-h') {
            console.log(`
多关键词并行爬取工具

功能：
  支持单个任务使用多个关键词并行运行，大幅提高效率

用法：
  node parallel-keywords-crawler.js [选项]

选项：
  -t, --task <任务名>         指定要运行的任务（必需）
  -k, --keywords <关键词>     指定关键词列表（逗号分隔，可选）
  --max-concurrent <数量>     最大并发数（默认：3）
  --headless                  无头模式运行
  --no-stealth                禁用隐身模式
  -h, --help                  显示帮助信息

示例：
  # 使用配置文件中的所有关键词并行运行
  node parallel-keywords-crawler.js --task amazon-jp

  # 指定特定关键词并行运行
  node parallel-keywords-crawler.js --task amazon-jp --keywords "ベビーフード,おむつ"

  # 设置最大并发数为5
  node parallel-keywords-crawler.js --task amazon-jp --max-concurrent 5

  # 无头模式运行
  node parallel-keywords-crawler.js --task amazon-de --keywords "Baby Foods,Toys" --headless

关键词配置：
  - 如果不指定 --keywords，将使用 tasks.config.js 中配置的所有关键词
  - 每个关键词会创建一个独立的任务实例
  - 任务实例会并行运行（受 max-concurrent 限制）
            `);
            process.exit(0);
        }
    }
    
    return options;
}

// 加载任务配置
function loadTaskConfig(taskName) {
    try {
        const taskPath = path.join(__dirname, 'tasks', taskName, 'index.js');
        if (!fs.existsSync(taskPath)) {
            throw new Error(`任务 "${taskName}" 不存在`);
        }
        
        const taskConfig = require(taskPath);
        return taskConfig;
        
    } catch (error) {
        throw new Error(`加载任务 "${taskName}" 失败: ${error.message}`);
    }
}

// 执行单个关键词的爬取任务
async function executeKeywordTask(browser, taskConfig, keyword, taskIndex, totalTasks) {
    const taskName = taskConfig.name || 'unknown';
    console.log(`\n📋 [${taskIndex + 1}/${totalTasks}] 开始执行: ${taskName} - 关键词: "${keyword}"`);
    
    try {
        // 创建新页面
        const page = await browser.newPage();
        
        // 设置用户代理
        await page.setExtraHTTPHeaders({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        });

        // 创建爬虫实例
        const crawler = new EcommerceCrawler();
        crawler.browser = browser;
        crawler.page = page;

        // 设置环境变量（关键词）
        const originalKeyword = process.env.CRAWL_KEYWORD;
        process.env.CRAWL_KEYWORD = keyword;

        // 执行爬取
        let result;
        if (typeof taskConfig.customCrawl === 'function') {
            result = await taskConfig.customCrawl(page, crawler);
        } else {
            await page.goto(taskConfig.url, {
                waitUntil: 'networkidle',
                timeout: taskConfig.crawlOptions?.timeout || 30000
            });
            
            const title = await page.title();
            result = {
                success: true,
                url: taskConfig.url,
                title: title,
                timestamp: new Date().toISOString()
            };
        }

        // 恢复环境变量
        if (originalKeyword) {
            process.env.CRAWL_KEYWORD = originalKeyword;
        } else {
            delete process.env.CRAWL_KEYWORD;
        }

        // 关闭页面
        await page.close();

        console.log(`✅ [${taskIndex + 1}/${totalTasks}] ${taskName} - "${keyword}" 执行成功`);
        
        return {
            taskName,
            keyword,
            config: taskConfig,
            success: true,
            ...result
        };

    } catch (error) {
        console.error(`❌ [${taskIndex + 1}/${totalTasks}] ${taskName} - "${keyword}" 执行失败:`, error.message);
        return {
            taskName,
            keyword,
            config: taskConfig,
            success: false,
            error: error.message,
            timestamp: new Date().toISOString()
        };
    }
}

// 批量并行执行（支持限制并发数）
async function runConcurrentKeywords(browser, taskConfig, keywords, maxConcurrent) {
    console.log(`\n🔀 并行模式: 最多同时执行 ${maxConcurrent} 个关键词（共 ${keywords.length} 个）\n`);
    
    const results = [];
    const totalTasks = keywords.length;

    // 分批执行
    for (let i = 0; i < keywords.length; i += maxConcurrent) {
        const batch = keywords.slice(i, i + maxConcurrent);
        const batchNumber = Math.floor(i / maxConcurrent) + 1;
        const totalBatches = Math.ceil(keywords.length / maxConcurrent);
        
        console.log(`\n📦 批次 ${batchNumber}/${totalBatches}: 执行 ${batch.length} 个关键词`);
        
        const batchResults = await Promise.all(
            batch.map((keyword, batchIndex) => 
                executeKeywordTask(browser, taskConfig, keyword, i + batchIndex, totalTasks)
            )
        );
        
        results.push(...batchResults);

        // 批次间延迟（除了最后一批）
        if (i + maxConcurrent < keywords.length) {
            const delay = 3000;
            console.log(`\n⏱️  批次完成，等待 ${delay}ms 后执行下一批...\n`);
            await new Promise(resolve => setTimeout(resolve, delay));
        }
    }

    return results;
}

// 保存结果到文件
function saveResults(results, taskName) {
    try {
        const outputDir = path.join(__dirname, 'output');
        if (!fs.existsSync(outputDir)) {
            fs.mkdirSync(outputDir, { recursive: true });
        }

        const timestamp = new Date().toISOString()
            .replace(/:/g, '-')
            .replace(/\./g, '-')
            .substring(0, 19);
        
        const filename = `parallel_${taskName}_${timestamp}.json`;
        const filepath = path.join(outputDir, filename);

        fs.writeFileSync(filepath, JSON.stringify(results, null, 2), 'utf-8');
        console.log(`\n💾 结果已保存到: ${filepath}`);
        
    } catch (error) {
        console.error('❌ 保存结果失败:', error.message);
    }
}

// 打印执行摘要
function printSummary(results, duration) {
    const successCount = results.filter(r => r.success).length;
    const failCount = results.length - successCount;

    console.log('\n' + '='.repeat(80));
    console.log(`📊 执行摘要 (多关键词并行模式)`);
    console.log('='.repeat(80));
    console.log(`总关键词数: ${results.length}`);
    console.log(`成功: ${successCount} ✅`);
    console.log(`失败: ${failCount} ❌`);
    console.log(`总耗时: ${duration}秒`);
    
    if (successCount > 0) {
        console.log(`\n✅ 成功的关键词:`);
        results.filter(r => r.success).forEach((r, i) => {
            console.log(`   ${i + 1}. "${r.keyword}"`);
        });
    }
    
    if (failCount > 0) {
        console.log(`\n❌ 失败的关键词:`);
        results.filter(r => !r.success).forEach((r, i) => {
            console.log(`   ${i + 1}. "${r.keyword}" - ${r.error}`);
        });
    }
    
    console.log('='.repeat(80) + '\n');
}

// 主函数
async function main() {
    console.log('========================================');
    console.log('    多关键词并行爬取工具');
    console.log('========================================\n');
    
    const options = parseArgs();
    
    // 验证必需参数
    if (!options.task) {
        console.error('❌ 错误: 必须指定任务名称');
        console.log('💡 使用 --help 查看帮助信息');
        process.exit(1);
    }
    
    try {
        // 加载任务配置
        console.log(`📥 正在加载任务配置: ${options.task}...\n`);
        const taskConfig = loadTaskConfig(options.task);
        console.log(`✅ 任务加载成功: ${taskConfig.name || options.task}`);
        
        // 获取关键词列表
        let keywords = options.keywords;
        if (!keywords) {
            // 使用配置文件中的关键词
            keywords = config.keywords && config.keywords[options.task];
            if (!keywords || keywords.length === 0) {
                console.error('❌ 错误: 未找到关键词');
                console.log('💡 请在 tasks.config.js 中配置关键词，或使用 --keywords 参数指定');
                process.exit(1);
            }
            console.log(`📋 使用配置文件中的关键词 (${keywords.length} 个)`);
        } else {
            console.log(`📋 使用指定的关键词 (${keywords.length} 个)`);
        }
        
        console.log(`\n🔍 关键词列表:`);
        keywords.forEach((keyword, i) => {
            console.log(`   ${i + 1}. "${keyword}"`);
        });
        
        // 连接数据库（如果启用）
        if (config.database && config.database.enabled) {
            try {
                await dbConnection.connect();
            } catch (error) {
                console.error('⚠️  数据库连接失败，将只保存到文件');
            }
        }
        
        // 启动浏览器
        const stealthMode = options.stealth ? '(Stealth 模式)' : '';
        console.log(`\n🚀 正在启动浏览器... ${stealthMode}`);
        
        let browser;
        const launchOptions = {
            headless: options.headless,
            slowMo: options.slowMo
        };
        
        if (options.stealth) {
            chromiumExtra.use(stealth);
            browser = await chromiumExtra.launch(launchOptions);
            console.log('✅ 浏览器启动成功！(已启用 Stealth 隐身模式)');
        } else {
            browser = await chromium.launch(launchOptions);
            console.log('✅ 浏览器启动成功！');
        }
        
        // 执行并行爬取
        const startTime = Date.now();
        const results = await runConcurrentKeywords(browser, taskConfig, keywords, options.maxConcurrent);
        const duration = ((Date.now() - startTime) / 1000).toFixed(2);
        
        // 关闭浏览器
        await browser.close();
        console.log('🔚 浏览器已关闭');
        
        // 打印摘要
        printSummary(results, duration);
        
        // 保存结果
        saveResults(results, options.task);
        
        // 关闭数据库连接
        if (config.database && config.database.enabled) {
            await dbConnection.disconnect();
        }
        
    } catch (error) {
        console.error('❌ 执行过程中出错:', error.message);
        console.error('   详情:', error.stack);
        process.exit(1);
    }
}

// 运行
if (require.main === module) {
    main().catch(console.error);
}

module.exports = main;

